package cc.rengu.igas.channel.nucc.core.packswitch;

import cc.rengu.igas.channel.nucc.common.constant.NuccParamConstant;
import cc.rengu.igas.channel.nucc.common.constant.NuccTreeNodeConstant;
import cc.rengu.igas.channel.nucc.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.nucc.core.realize.NuccEncSignService;
import cc.rengu.igas.channel.nucc.core.realize.impl.NuccEncSignServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.SysParamMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SysParamMapperImpl;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.base.TimeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 与网联通讯解包前、解包后、组包前及组后的处理类
 * Created by
 */
public class NuccServerPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {
    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        String rcvMsg = new String(bytes, StandardCharsets.UTF_8);
        XmlTreeUtil tree = new XmlTreeUtil();
        /* 赋值默认机构、渠道、交易细分 */
        tree.setXmlTreeStringValue(TreeNodeConstant.INST_ID, NuccParamConstant.DEFAULT_INSTID);
        tree.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, NuccParamConstant.TUNL_ID_NUCC_ISS);
        tree.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, NuccParamConstant.DEFAULT_BIZ_TYPE);
        String srcData = pattern("(<root.*</root>)", rcvMsg);
        if (null != srcData) {
            rglog.debug("srcData:[{}]", srcData);
            tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_BLOCK, srcData);
        } else {
            rglog.error("找不到需要签名的字符串!");
            throw new Exception("找不到需要签名的字符串!");
        }

        String signData = pattern("</root>.*\\{S:(.*)?}", rcvMsg);
        if (null != signData) {
            rglog.debug("signData:[{}]", signData);
            tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN, signData);
        } else {
            rglog.error("找不到签名字符串!");
            // todo throw new Exception("找不到签名字符串!");
        }
        /* 获取通道配置信息 */
        String instId = tree.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
        DstChannelInfo dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, NuccParamConstant.TUNL_ID_NUCC);
        if (null == dstChannelInfo) {
            rglog.error("获取通道<{}>配置信息失败!", NuccParamConstant.TUNL_ID_NUCC);
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelInfo.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            tree.setXmlTreeStringValue(NuccTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
        }
        return srcData.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        CertInfo certInfo;
        NuccEncSignService signService = new NuccEncSignServiceImpl();

        String sign = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN);
        if (null == sign) {
            rglog.debug("无签域，不进行签名校验!");
            return 0;
        }
        /* 获取数字签名字符串 */
        String signBlock = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_BLOCK);
        rglog.debug("加签Block:<{}>", signBlock);
        rglog.debug("sign:<{}>", sign);
        /* 获取敏感信息加密证书 */
        String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.SEC_PLAN_INFO_LIST);
        List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
        Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(NuccParamConstant.VERIFY_CERT_TYPE)).findFirst();
        if (secPlanInfoOpt.isPresent()) {
            CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
            certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            /* 验证签名 */
            if (signService.verifySignString(certInfo, sign, signBlock)) {
                rglog.info("签名验证成功!");
                xmlTreeUtil.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_VERIFY_FLAG, "1");
            } else {
                rglog.error("签名验证失败!");
                xmlTreeUtil.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_VERIFY_FLAG, "0");
            }

        } else {
            rglog.error("未获取到验签证书!");
            return -1;
        }

        xmlTreeUtil.deleteXmlTreeNode(NuccTreeNodeConstant.EPCC_SIGN_BLOCK);
        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        XmlTreeUtil tree = new XmlTreeUtil();

        /*报文头部分字段赋值*/
        /* 返回EPCC时发起方所属机构标识进行替换 */
        //tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ISSR_ID, NuccParamConstant.EPCC_DEFAULT_INSTID);

        String time = TimeUtil.getDateTime("yyyy-MM-dd'T'HH:mm:ss");
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SND_DT, time);
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_TRX_DT_TM, time);
        tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SYS_RTN_TM, time);

//		/* 获取敏感信息加密证书 */
//		String secPlanInfoListString = tree.getXmlTreeStringValue(NuccTreeNodeConstant.SEC_PLAN_INFO_LIST);
//		List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
//		Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item ->item.getSecPlanType().equals(NuccParamConstant.SIGN_CERT_TYPE)).findFirst();
//		if (secPlanInfoOpt.isPresent()){
//			CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
//			CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
//			//证书从数据库获取
//			tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_SIGN_SN,certInfo.getCertDn());
//			//证书从数据库获取
//			tree.setXmlTreeObjectValue(NuccTreeNodeConstant.EPCC_PRIVATE_CER_INFO,certInfo);
//		}
//		String aesKey = tree.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ENC_KEY);
//		if(aesKey != null){
//			//用公钥对密钥进行加密
//			Optional<SecPlanInfo> secPlanInfoOptPub = secPlanInfoList.stream().filter(item ->item.getSecPlanType().equals(NuccParamConstant.VERIFY_CERT_TYPE)).findFirst();
//			if (secPlanInfoOptPub.isPresent()){
//				CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
//				CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOptPub.get().getSecPlanId() + secPlanInfoOptPub.get().getSecPlanType());
//				//证书从数据库获取
//				tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_ENC_SN,certInfo.getCertDn());
//				NuccEncSignService signService = new NuccEncSignServiceImpl();
//				tree.setXmlTreeStringValue(NuccTreeNodeConstant.EPCC_DGTL_ENVLP,signService.encryptedInfo(certInfo,"01|"+aesKey));
//			}
//
//		}
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String signBlock = new String(bytes);  //StringUtil.binaryToHexString(bytes);
//		/* 获取敏感信息加密证书 */
//		CertInfo certInfo = (CertInfo) xmlTreeUtil.getXmlTreeObjectValue(NuccTreeNodeConstant.EPCC_PRIVATE_CER_INFO,CertInfo.class);
//		if (certInfo == null){
//			rglog.error("获取不到签名证书!");
//			return bytes;
//		}
//		/* 加签 */
//		NuccEncSignService signService = new NuccEncSignServiceImpl();
//		String signData = signService.generateSignString(certInfo,signBlock);
//		String sign = String.format("{S:%s}", signData);
//		String sndMsg = new String(bytes, StandardCharsets.UTF_8) + "\r\n" + sign;
        String sndMsg = new String(bytes, StandardCharsets.UTF_8) + "\r\n";
        /* 响应信息中http头部域设置Content-Type */
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/MsgTp", xmlTreeUtil.getXmlTreeStringValue(NuccTreeNodeConstant.EPCC_MSG_TP));
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/method", "POST");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Connection", "Keep-Alive");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/xml;charset=utf-8");
        xmlTreeUtil.setXmlTreeIntValue("_MESSAGEHEAD/http/Content-Length", sndMsg.getBytes(StandardCharsets.UTF_8).length);
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/ArgList", "MsgTp:Content-Type:Content-Length:method:Connection");
        return sndMsg.getBytes();

    }

    private static String pattern(String regex, String str) {
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(str);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return null;
        }
    }
}
